import { useMemo, useRef } from 'react'
import { v7 as uuidv7 } from 'uuid'
import { MessageType, MessageRoleEnum, Chat, ChatOptions } from '@/types'
import { getAssistant, AssistantType } from '@/funcs/models'
import { useAtomValue, useAtom } from 'jotai'
import { useTranslation } from 'react-i18next'
import useMessage from './useMessage'
import { showAlertDialog } from '@/components/Base/Alert'
import {
  currentAssistantAtom,
  currentChatAtom,
  autoGenerateTitleAtom,
  chatsAtom,
  currentChatIdAtom,
  defaultPrompt,
} from '@/atoms'

function nameConversation(msgs: MessageType[]): MessageType[] {
  const useMsg: MessageType = {
    id: '13',
    role: 'user',
    content: `
    Based on the chat history, give this conversation a name. 
    Keep it short - 20 characters max and just word without marks.
    Just provide the name, nothing else. `,
  }

  return [
    ...msgs.filter(m => m.role !== 'system').slice(0, 4),
    useMsg,
  ]
}

export default function useChat() {
  const { t } = useTranslation()
  const currentAssistant = useAtomValue(currentAssistantAtom)
  const currentChat = useAtomValue(currentChatAtom)
  const autoGenerateTitle = useAtomValue(autoGenerateTitleAtom)
  const [, setChats] = useAtom(chatsAtom)
  const [, setcurrentChat] = useAtom(currentChatIdAtom)
  const abortTag = useRef(false)
  const { insertMessage, updateMessage } = useMessage()

  const client: AssistantType | null = useMemo(() => {
    if (currentAssistant && currentChat) {
      return getAssistant({ ...currentAssistant, ...currentChat.options })
    }
    else {
      return null
    }
  }, [currentAssistant, currentChat])

  const abortResponse = () => {
    abortTag.current = true
  }

  const getResMessage = async () => {
    if (!client) {
      showAlertDialog({
        content: t('need assistant content'),
      })
      return
    }

    const assistantMessage: MessageType = {
      id: uuidv7(),
      role: MessageRoleEnum.Assistant,
      content: '',
      aiProvider: currentAssistant!.modelApi,
      model: currentAssistant!.modelName,
    }

    insertMessage(assistantMessage)

    try {
      const msg = [...currentChat!.messages]
      if (msg.length > 0 && msg[msg.length - 1].role === MessageRoleEnum.Assistant) {
        msg.pop() // 把最后一条插入的assistant消息移除,防止空数据，有些模型需要message不为空
      }
      const { stream, abort, deepChunk } = await client.chat(msg)
      let text = ''
      for await (const chunk of stream) {
      // @ts-expect-error chatResponse | ChatCompletionChunk
        const str = deepChunk(chunk)
        if (str) {
          text += str
          updateMessage({ ...assistantMessage, content: text }) // debounce effect not well
        }
        if (abortTag.current) {
          abort()
        }
      }
    }
    catch (e) {
      // 这里可以把最后一条插入消息移除
      showAlertDialog({
        title: 'Error',
        content: (e as Error).message,
      })
    }
  }

  const generateChatTitle = async () => {
    if (
      client
      && autoGenerateTitle
      && currentChat!.name === 'Untitled'
      && currentChat!.messages.length >= 2
    ) {
      const { stream, deepChunk } = await client.chat(nameConversation(currentChat!.messages))
      let text = ''
      for await (const chunk of stream) {
        // @ts-expect-error chatResponse | ChatCompletionChunk
        const str = deepChunk(chunk)
        if (str) {
          text += str
        }
      }
      modifyChatInfo({ id: currentChat!.id, name: text })
    }
  }

  const newChat = () => {
    const newChat: Chat = {
      id: uuidv7(),
      name: 'Untitled',
      messages: [
        {
          id: uuidv7(),
          role: MessageRoleEnum.System,
          content: currentAssistant?.prompt || defaultPrompt,
        },
      ],
      options: {
        store: false,
        reasoning_effort: 'medium',
        frequency_penalty: 0,
        logprobs: false,
        top_logprobs: null,
        max_tokens_limit: false,
        max_completion_tokens: null,
        n: 1,
        presence_penalty: 0,
        temperature: 1,
      },
    }
    setChats((chats: Chat[]) => [...chats, newChat])
    switchChat(newChat.id)
  }

  const switchChat = (chatId: string) => {
    setcurrentChat(chatId)
  }

  const modifyChatInfo = (params: { id: string, name?: string, options?: ChatOptions, category?: string }) => {
    setChats(chats =>
      chats.map((s) => {
        if (s.id === params.id) {
          return { ...s, ...params }
        }
        return s
      }),
    )
  }

  const removeChat = (chat: Chat) => {
    setChats(chats => chats.filter(s => s.id !== chat.id))
  }

  const clearChats = () => {
    setChats([])
    newChat()
  }

  const copyChat = (source: Chat) => {
    const newSession = { ...source }
    newSession.id = uuidv7()
    setChats((chats) => {
      let originIndex = chats.findIndex(s => s.id === source.id)
      if (originIndex < 0) {
        originIndex = 0
      }
      const newSessions = [...chats]
      newSessions.splice(originIndex + 1, 0, newSession)
      return newSessions
    })
  }

  return {
    abortResponse,
    getResMessage,
    generateChatTitle,
    newChat,
    modifyChatInfo,
    switchChat,
    removeChat,
    clearChats,
    copyChat,
  }
}
